import 'dart:convert';
import 'dart:io';

import 'package:common_utils/common_utils.dart';
import 'package:dio/adapter.dart';
import 'package:dio/dio.dart';
import 'package:example/main.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_tenma_venture_http/config/http_base_options.dart';
import 'package:flutter_tenma_venture_http/config/http_config.dart';
import 'package:flutter_tenma_venture_http/models/base_model.dart';
import 'package:flutter_tenma_venture_http/service/http_service.dart';
import 'package:flutter_tenma_venture_http/service/tm_encryption_tool.dart';
import 'package:flutter_tenma_venture_http/utils/cache_utils.dart';

///http请求成功回调
typedef ApiHttpSuccessCallback<T> = void Function(ApiBaseModel data);

class ApiDioManager{
  // 单例
  factory ApiDioManager() => _getInstance();

  static ApiDioManager _instance;

  static ApiDioManager _getInstance() {
    if (_instance == null) {
      _instance = ApiDioManager._init();
    }
    return _instance;
  }

  Dio _dio;

  ApiDioManager._init() {
    print("DioManager._init");
  }

  /// 初始化
  void init(Dio dio) {
    if (_dio == null) {
      _dio = dio;

      // 请求与响应拦截器
      _dio.interceptors.add(OnReqResInterceptors());
      // 异常拦截器
      _dio.interceptors.add(OnErrorInterceptors());

      HttpBaseOptions httpBaseOptions = _dio.options;
      if (httpBaseOptions.isProxy) {
        (_dio.httpClientAdapter as DefaultHttpClientAdapter)
            .onHttpClientCreate = (client) {
          client.findProxy = (url) {
            ///设置代理 电脑ip地址
            return "PROXY ${httpBaseOptions.proxyUrl}";
          };

          ///忽略证书
          client.badCertificateCallback =
              (X509Certificate cert, String host, int port) => true;
        };
      }
    }
  }

  /// get请求
  Future get(
      {@required String url,
        Map<String, dynamic> params,
        HttpSuccessCallback successCallBack,
        HttpFailureCallback errorCallBack,
        Map<String, dynamic> header}) async {
    return await requestHttp(url,
        method: TMDioMethod.get,
        params: params,
        successCallBack: successCallBack,
        errorCallBack: errorCallBack,
        header: header);
  }

  /// post 请求
  Future post(
      {@required String url,
        Map<String, dynamic> params,
        HttpSuccessCallback successCallBack,
        HttpFailureCallback errorCallBack,
        Map<String, dynamic> header}) async {
    return await requestHttp(url,
        method: TMDioMethod.post,
        params: params,
        successCallBack: successCallBack,
        errorCallBack: errorCallBack,
        header: header);
  }

  /// Dio request 方法
  Future requestHttp(String url,
      {TMDioMethod method = TMDioMethod.get,
        Map<String, dynamic> params,
        FormData formData,
        HttpSuccessCallback successCallBack,
        HttpFailureCallback errorCallBack,
        UploadFileProgressCallback uploadFileProgressCallback,
        bool isUpload = false,
        Map<String, dynamic> header}) async {
    HttpBaseOptions httpBaseOptions = _dio.options as HttpBaseOptions;

    if (httpBaseOptions.isEncrypt) {
      Map enData = TMEncryptionTool.tm_encryption(params);

      if (enData['code'] != 200) {
        if (errorCallBack != null) {
          errorCallBack(enData['code'], enData['msg']);
        }
        return;
      }

      if (enData['headers'] != null) {
        Map headers = Map<String, dynamic>.from(enData['headers']);
        _dio.options.headers.addAll(headers);
      }
      if (enData['params'] != null) {
        params = Map<String, dynamic>.from(enData['params']);
      }
    }

    if (header != null && (header is Map)) {
      _dio.options.headers.addAll(header);
    }

    try {
      Response response;
      // 不同请求方法，不同的请求参数。按实际项目需求分，这里 get 是 queryParameters，其它用 data. FormData 也是 data
      // 注意: 只有 post 方法支持发送 FormData.

      if (httpBaseOptions.cacheMode == CacheMode.FIRST_CACHE_THEN_REQUEST) {
        getCacheCallback(url, params, successCallBack);
      }

      switch (method) {
        case TMDioMethod.get:
          response = await _dio.request(url,
              queryParameters: params, options: Options(method: 'get'));
          break;
        case TMDioMethod.put:
          response = await _dio.request(url,
              queryParameters: params, options: Options(method: 'put'));
          break;
        case TMDioMethod.delete:
          response = await _dio.request(url,
              queryParameters: params, options: Options(method: 'delete'));
          break;
        default:
          if (formData != null) {
            response = await _dio
                .request(url, data: formData, options: Options(method: 'post'),
                onSendProgress: (received, total) {
                  uploadFileProgressCallback(received, total);
                });
          } else {
            response = await _dio.request(url,
                queryParameters: params,
                data: params,
                options: Options(method: 'post'));
          }
      }

      // JSON 序列化, Response<dynamic> 转 Map<String, dynamic>

      final BaseModel model = BaseModel.fromJson(response.data);

      if (model.errCode == 200) {
        // 保存缓存
        if (httpBaseOptions.cacheMode != CacheMode.NO_CACHE) {
          LogUtil.v("save cache");
          CacheUtils.saveCache(
              CacheUtils.getCacheKeyFromPath(url, params ?? {}),
              json.encoder.convert(response.data));
        }

        if (successCallBack != null) {
          successCallBack(model);
        }
      } else if (model.errCode >= 500 && model.errCode <= 510) {
        doErrorCallback(httpBaseOptions, url, params, successCallBack,
            errorCallBack, model.errCode, model.message);
      } else if (errorCallBack != null) {
        doErrorCallback(httpBaseOptions, url, params, successCallBack,
            errorCallBack, model.errCode, model.message);
      }
    } on DioError catch (e) {
      if (errorCallBack != null && e.type != DioErrorType.CANCEL) {
        doErrorCallback(httpBaseOptions, url, params, successCallBack,
            errorCallBack, 0, e.message);
      }
    } catch (e) {
      LogUtil.e(e);
      if (errorCallBack != null) {
        doErrorCallback(httpBaseOptions, url, params, successCallBack,
            errorCallBack, 0, '未知错误');
      }
    }
  }

  /// 错误回调
  void doErrorCallback(
      HttpBaseOptions httpBaseOptions,
      String url,
      Map<String, dynamic> params,
      HttpSuccessCallback successCallBack,
      HttpFailureCallback errorCallBack,
      int errorCode,
      String errorMsg) {
    if (httpBaseOptions.cacheMode == CacheMode.REQUEST_FAILED_READ_CACHE) {
      getCacheCallback(url, params, successCallBack,
          isErrorCallBack: true,
          errorCallBack: errorCallBack,
          errorCode: errorCode,
          errorMsg: errorMsg);
    } else {
      if (errorCallBack != null) {
        errorCallBack(errorCode, errorMsg);
      }
    }
  }

  /// 获取缓存并返回
  void getCacheCallback(String url, Map<String, dynamic> params,
      HttpSuccessCallback successCallBack,
      {bool isErrorCallBack = false,
        HttpFailureCallback errorCallBack,
        int errorCode,
        String errorMsg}) {
    //先获取缓存，在获取网络
    CacheUtils.getCache(url, params ?? {}).then((list) {
      if (list.length > 0) {
        LogUtil.v("getCache");
        String cacheResponseData = list[0]['value'];
        LogUtil.v(cacheResponseData);
        final BaseModel cacheModel =
        BaseModel.fromJson(jsonDecode(cacheResponseData));
        if (successCallBack != null) {
          successCallBack(cacheModel);
        }
      } else {
        // 缓存为空
        if (isErrorCallBack) {
          errorCallBack(errorCode, errorMsg);
        }
      }
    });
  }
}